import Task from './queue-task'
import { QueueInterface } from './queue-interface'

/**
 * 任务队列
 * @author wurenlong
 */
export default class Queue extends QueueInterface {
  constructor(id) {
    super()
    this.id = id || this.getId()
    this.locked = false
    this.store = []
    this.thens = []
  }

  getId() {
    return new Date().getTime() + parseInt(Math.random() * 10000)
  }

  isEmpty() {
    return this.store.length === 0
  }

  size() {
    return this.store.length
  }

  addTask(task, params, hooks) {
    return new Promise((resolve = ()=>{}, reject = ()=>{}) => {
      this.store.push(new Task({ task, params, hooks, resolve, reject }))
    })
  }

  lock() {
    this.locked = true
  }

  /**
   * 队列执行
   */
  start() {
    this.runTask(this.store.shift())
  }

  /**
   * 并发执行
   */
  startAll() {
    if (this.store.length === 0) {
      this.start()
    } else {
      const size = this.store.length
      let queueLength = size
      for (let i = 0; i < size; i++) {
        const task = this.store.shift()
        if (!task) continue
        task.start(this.id).then(({ reslut, id }) => {
          task.resolve(reslut)
        }).catch(({ err, id }) => {
          if (task.reject) {
            task.reject(err)
          }
        }).finally(() => {
          queueLength = queueLength - 1
          if (queueLength <= 0) {
            this.thens.forEach(cb => cb())
          }
        })
      }
    }
  }

  then(callback) {
    this.thens.push(callback)
  }

  runTask(task) {
    if (task) {
      this.locked = true
      const that = this
      task.start(this.id)
        .then(({ reslut, id }) => {
          task.resolve(reslut)
          this.id = id || this.getId()
          if (!this.isEmpty()) {
            setTimeout(() => {
              that.runTask(that.store.shift())
            }, 4)
          } else {
            this.thens.forEach(cb => cb())
          }
        })
        .catch(({ err, id }) => {
          if (task.reject) {
            task.reject(err)
          }
          this.id = id || this.getId()
          if (!this.isEmpty()) {
            setTimeout(() => {
              that.runTask(that.store.shift())
            }, 4)
          } else {
            this.thens.forEach(cb => cb())
          }
        })
    } else {
      this.locked = false
      this.thens.forEach(cb => cb())
    }
  }
}
